#include "jsonhead.h"
#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <chrono>
#include <ctime>
#include <unordered_map>
#include <functional>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <semaphore.h>
#include <atomic>
#include "group.hpp"
#include "usr.hpp"
#include "public.hpp"
#include <err.h>
#include <cstring>
using namespace std;

User currentUser;        // 记录当前用户的消息
vector<User> friendlist; // 当前用户好友列表
vector<group> grouplist; // 当前用户的群组
// 记录登录状态
atomic_bool isLoginSuccess{false}; // 操作都是原子的
// 用于读写线程之间的通信
sem_t rwsem;
bool isMainMenuRunning = false;


void mainMenu(int clientfd);
// 一共有两个线程运行，主线程负责与用户交互IO
// 新线程负责与服务器交流并打印消息
void readtaskHandler(int clientfd);

// 获取系统时间（聊天信息需要添加时间信息）
string getCurrentTime();
int g_clientfd = 0;
void help(int, string);
void chat(int, string);
void addfriend(int, string);
void creategroup(int, string);
void addgroup(int, string);
void groupchat(int, string);
void loginout(int, string);
void showfriend(int, string);
void showgroup(int, string);
void leavemessage(int, string);
void showUserData(int,string);
// 系统支持的客户端命令列表
unordered_map<string, string> commandMap = {
    {"help", "显示所有支持的命令，格式help"},
    {"chat", "一对一聊天，格式chat:friendid:message"},
    {"addfriend", "添加好友，格式addfriend:friendid"},
    {"creategroup", "创建群组，格式creategroup:groupname:groupdesc"},
    {"addgroup", "加入群组，格式addgroup:groupid"},
    {"groupchat", "群聊，格式groupchat:groupid:message"},
    {"loginout", "注销，格式loginout"},
    {"showfriend", "显示所有的好友，格式showfriend"},
    {"showgroup", "显示所有的群组，格式showgroup"},
    {"leavemessage", "显示离线消息，格式leavemessage"},
    {"showUserData","显示用户信息，格式showUserData"}
};


void showUserData(int client ,string str)
{
    cout << "======================login user======================" << endl;
    cout << "current login user => id:" << currentUser.getid() << " name:" << currentUser.getname() << endl;
    /*
    cout << "----------------------friend list---------------------" << endl;
    if (!friendlist.empty())
    {
        for (User &user : friendlist)
        {
            cout << user.getid() << " " << user.getname() << " " << user.getstate() << endl;
        }
    }
    cout << "----------------------group list----------------------" << endl;
    if (!grouplist.empty())
    {
        int i = 0;
        for (group &gp : grouplist)
        {
            i++;
            cout << "第" << i << "组：   " << gp.getid() << " " << gp.getname() << " " << gp.getdec() << endl;
            int j = 0;
            for (groupuser &user : gp.getgroupuser())
            {
                j++;
                cout << "第" << j << "个成员：      " << user.getid() << " " << user.getname() << " " << user.getstate()
                     << " " << user.getrole() << endl;
            }
        }
    }
    */
    cout << "======================================================" << endl;
}
// 回调函数列表

unordered_map<string, function<void(int, string)>> commandHandlerMap = {
    {"help", help},
    {"chat", chat},
    {"addfriend", addfriend},
    {"creategroup", creategroup},
    {"addgroup", addgroup},
    {"groupchat", groupchat},
    {"loginout", loginout},
    {"showfriend", showfriend},
    {"showgroup", showgroup},
    {"showUserData",showUserData},
    {"leavemessage", leavemessage}
};



void help(int client, string str)
{
    cout << "======================  命令列表  ======================" << endl;
    for (auto it : commandMap)
    {
        cout << it.first << ":   " << it.second << endl;
    }
    cout << endl;
}

// 一对一聊天回调函数
void chat(int clientfd, string str)
{
    int idx = str.find(":");
    if (idx == -1)
    {
        cerr << "chat command invalid!" << endl;
        return;
    }
    int friendid = atoi(str.substr(0, idx).c_str());
    string message = str.substr(idx + 1, str.size() - idx);
    Json::Value value;
    value["msgid"] = 5;
    value["id"] = currentUser.getid();
    value["name"] = currentUser.getname();
    value["toid"] = friendid;
    value["message"] = message;
    value["time"] = getCurrentTime();
    Json::FastWriter fastwriter;
    string ret = fastwriter.write(value);
    int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send chat msg err: " << strerror(errno) << endl;
        return;
    }
}

void addfriend(int clientfd, string str)
{
    int friendid = atoi(str.c_str());
    Json::Value value;
    value["msgid"] = 7;
    value["id"] = currentUser.getid();
    value["friendid"] = friendid;
    Json::FastWriter fastwriter;
    string ret = fastwriter.write(value);
    int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send addfriend msg err: " << strerror(errno) << endl;
        return;
    }
}

void creategroup(int clientfd, string str)
{
    int idx = str.find(":");
    if (idx == -1)
    {
        cerr << "creategroup command invalid!: " << endl;
        return;
    }

    string groupname = str.substr(0, idx);
    string groupdec = str.substr(idx + 1, str.size() - idx);
    Json::Value value;
    value["msgid"] = 8;
    value["id"] = currentUser.getid();
    value["groupname"] = groupname;
    value["groupdec"] = groupdec;
    Json::FastWriter fastwrite;
    string ret = fastwrite.write(value);
    int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send creategroup msg err: " << strerror(errno) << endl;
        return;
    }
}

void addgroup(int clientfd, string str)
{
    int groupid = atoi(str.c_str());
    Json::Value value;
    value["msgid"] = 9;
    value["id"] = currentUser.getid();
    value["groupid"] = groupid;
    Json::FastWriter fastwriter;
    string ret = fastwriter.write(value);
    int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send addgroup msg err: " << strerror(errno) << endl;
        return;
    }
}

void groupchat(int clientfd, string str)
{
    int idx = str.find(":");
    if (idx == -1)
    {
        cerr << "groupchat command invalid" << endl;
        return;
    }
    int groupid = atoi(str.substr(0, idx).c_str());
    string message = str.substr(idx + 1, str.size() - idx);
    Json::Value value;
    value["msgid"] = 6;
    value["userid"] = currentUser.getid();
    value["name"] = currentUser.getname();
    value["groupid"] = groupid;
    value["messagge"] = message;
    value["time"] = getCurrentTime();
    Json::FastWriter fastwriter;
    string ret = fastwriter.write(value);
    int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send groupchat msg err: " << strerror(errno) << endl;
        return;
    }
}

void loginout(int clientfd, string str)
{
    Json::Value value;
    int userid = currentUser.getid();
    value["msgid"] = 13;
    value["id"] = userid;
    Json::FastWriter fastwriter;
    string ret = fastwriter.write(value);
    int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "loginout groupchat msg err: " << strerror(errno) << endl;
        return;
    }
}

void showfriend(int clientfd, string str)
{
    Json::Value value;
    int userid = currentUser.getid();
    value["msgid"] = 11;
    value["userid"] = userid;
    Json::FastWriter fastwriter;
    string ret = fastwriter.write(value);
    int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "showfriend groupchat msg err: " << strerror(errno) << endl;
        return;
    }
}

void showgroup(int clientfd, string str)
{
    Json::Value value;
    int userid = currentUser.getid();
    value["msgid"] = 10;
    value["id"] = userid;
    Json::FastWriter fastwriter;
    string ret = fastwriter.write(value);
    int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "showgroup groupchat msg err: " << strerror(errno) << endl;
        return;
    }
}

void leavemessage(int clientfd, string str)
{
    Json::Value value;
    int userid = currentUser.getid();
    value["msgid"] = LEAVE_MESSAGE_MSG;
    value["userid"] = userid;
    cout << userid << endl;
    Json::FastWriter fastwriter;
    string ret = fastwriter.write(value);
    int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "leavemessage groupchat msg err: " << strerror(errno) << endl;
        return;
    }
}

void mainMenu(int clientfd)
{
    help(0, "");
    string buff;
    while (isMainMenuRunning)
    {
        // 调用回调函数
        cout << "请选择功能: ";
        getline(cin, buff);
        string cmd;
        int idx = buff.find(":");
        if (idx == -1)
        {
            cmd = buff;
        }
        else
        {
            // 提取选项
            cmd = buff.substr(0, idx);
        }
        auto it = commandHandlerMap.find(cmd);
        if (it == commandHandlerMap.end())
        {
            cerr << "command invalid! example!" << endl;
            continue;
        }
        else
        {
            // 执行回调函数
            it->second(clientfd, buff.substr(idx + 1, buff.size() - idx));
        }
    }
}

// 获取系统时间（聊天信息需要添加时间信息）
string getCurrentTime()
{
    auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    struct tm *ptm = localtime(&tt);
    char date[60] = {0};
    sprintf(date, "%d-%02d-%02d %02d:%02d:%02d",
            (int)ptm->tm_year + 1900, (int)ptm->tm_mon + 1, (int)ptm->tm_mday,
            (int)ptm->tm_hour, (int)ptm->tm_min, (int)ptm->tm_sec);
    return std::string(date);
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        cerr << "command invalid! example: ./ChatClient ip port" << endl;
        exit(-1);
    }
    char *ip = argv[1];
    int port = atoi(argv[2]);
    // 创建客户端Socket
    int clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if (clientfd == -1)
    {
        cerr << "client cteate err: " << strerror(errno) << endl;
        exit(-1);
    }
    g_clientfd = clientfd;
    // 绑定
    sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);
    addr.sin_port = htons(port);
    socklen_t len = sizeof(addr);
    // 连接服务器
    int ret = connect(clientfd, (sockaddr *)&addr, len);
    if (ret == -1)
    {
        cerr << "connect err: " << strerror(errno) << endl;
        close(clientfd);
        exit(-1);
    }

    // 初始化读写线程通信用的信号量
    sem_init(&rwsem, 0, 0);

    std::thread readtask(readtaskHandler, clientfd);

    for (;;)
    { // 显示首页面菜单 登录、注册、退出
        cout << "========================" << endl;
        cout << "1. login" << endl;
        cout << "2. register" << endl;
        cout << "3. quit" << endl;
        cout << "========================" << endl;
        cout << "choice:";
        int choice = 0;
        cin >> choice;
        cin.get(); // 读掉缓冲区残留的回车
        switch (choice)
        {
        case 1: // 登录业务
        {
            int id;
            string psd;
            cout << "请输入userid: ";
            cin >> id;
            cin.get(); // 清理掉缓冲区的回车
            cout << "请输入password: ";
            getline(cin, psd);
            // 严重账号密码是否正确
            Json::Value value;
            value["msgid"] = 1;
            value["id"] = id;
            value["password"] = psd;
            Json::FastWriter fastwriter;
            string ret = fastwriter.write(value);
            isLoginSuccess = false;
            int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
            if (len == -1)
            {
                cerr << "send err: " << strerror(errno) << endl;
            }

            // 等待新线程处理登录信息逻辑
            sem_wait(&rwsem);
            if (isLoginSuccess) // 如果登录成功
            {
                // 执行业务业务流程
                //  进入聊天主菜单页面
                isMainMenuRunning = true;
                mainMenu(clientfd);
            }
        }
        break;
        case 2: // 注册业务
        {
            string name, pwd;
            cout << "请输入username: ";
            getline(cin, name);
            cout << "请输入password: ";
            getline(cin, pwd);
            Json::Value value;
            value["msgid"] = 3;
            value["name"] = name;
            value["password"] = pwd;
            Json::FastWriter fastwriter;
            string ret = fastwriter.write(value);
            isLoginSuccess = false;
            int len = send(clientfd, ret.c_str(), strlen(ret.c_str()) + 1, 0);
            if (len == -1)
            {
                cerr << "send err: " << strerror(errno) << endl;
            }
            sem_wait(&rwsem); // 等待信号量，执行注册逻辑
        }
        break;
        case 3:
        {
            close(clientfd);
            // 销毁互斥锁
            sem_destroy(&rwsem);
            exit(0);
        }
        break;
        default:
        {
            cout << "没有该选项，请重新输入" << endl;
        }
        break;
        }
    }
    return 0;
}

void dologin(Json::Value &js)
{
    int num = js["errno"].asInt();
    if (num != 0) // 登录失败的情况
    {
        string ret = js["errmsg"].asString();
        isLoginSuccess = false;
        cerr << ret << endl;
    }
    else // 登录成功的情况
    {
        isLoginSuccess = true;
        currentUser.setid(js["id"].asInt());
        currentUser.setname(js["name"].asString());
        // 填充好友列表，离线消息列表，群组列表

        string ret = js["errmsg"].asString();
        cout << ret << endl;
        cout << "======================================================" << endl;
    }
}

void doreg(Json::Value &js)
{
    int num = js["errno"].asInt();
    if (num != 0)
    {
        cerr << "name is already exist, register error!" << endl;
    }
    else
    {
        cout << "name register success, userid is " << js["id"].asInt() << ", do not forget it!" << endl;
    }
}

void readtaskHandler(int clientfd)
{
    for (;;)
    {
        char buff[1024] = {0};
        int len = recv(clientfd, buff, 1024, 0);
        if (len == -1 || len == 0)
        {
            close(clientfd);
            exit(-1);
        }
        Json::Value value;
        Json::Reader reader;
        reader.parse(buff, value);
        int msgid = value["msgid"].asInt();
        if (msgid == LOGIN_MSG_ACK)
        {
            dologin(value);
            sem_post(&rwsem); // 通知主线程，登录结果处理完成
            continue;
        }
        else if (msgid == REG_MSG_ACK)
        {
            doreg(value);
            sem_post(&rwsem); // 通知主进程，注册结果处理完成
            continue;
        }
        else if (msgid == ONE_CHAT_MSG) // 一对一聊天
        {
            // 接收消息
            cout << value["time"].asString() << " [" << value["id"].asInt() << "]" << value["name"].asString() << " said: " << value["message"].asString() << endl;
            continue;
        }
        else if (GROUP_CHAT_MSG == msgid) // 群聊天
        {
            cout << "群消息[" << value["groupid"].asInt() << "]:" << value["time"].asString() << " [" << value["userid"].asInt() << "]" << value["name"].asString()<< " said: " << value["message"].asString() << endl;
            continue;
        }
        else if (msgid == SHOW_GROUP_ACK) // 群列表
        {
            Json::Value groupll = value["groupmsg"];
            for (int i = 0; i < groupll.size(); i++)
            {
                Json::Value groupi;
                string groupii = groupll[i].asString();
                reader.parse(groupii, groupi);
                cout << "[  " << i + 1 << "  ]----"
                     << "id:  " << groupi["id"].asInt() << "  name:  " << groupi["name"].asString() << "  dec:  " << groupi["dec"].asString() << endl;
                // 打印组内成员
                Json::Value data = groupi["groupuser"];
                for (int i = 0; i < data.size(); i++)
                {
                    // 字符串转换为Json
                    Json::Reader reader;
                    Json::Value friend_single;
                    reader.parse(data[i].asString(), friend_single);
                    cout << "【  第" << i + 1 << "成员  】----"
                         << "userid:  " << friend_single["userid"].asInt() << "  name:  " << friend_single["name"].asString() << "  state:  " << friend_single["state"].asString() << "   role    " << friend_single["role"] << endl;
                }
                cout<<endl;
            }
            continue;
        }
        else if (msgid == SHOW_FRIENDS_ACK) // 好友列表
        {
            Json::Value friendll = value["friend"];
            for (int i = 0; i < friendll.size(); i++)
            {
                // 字符串转换为Json
                Json::Reader reader;
                Json::Value friendi;
                string friendii = friendll[i].asString();
                reader.parse(friendii, friendi);
                cout << "[  " << i + 1 << "  ]----"
                     << "id:  " << friendi["id"].asInt() << "  name:  " << friendi["name"].asString() << "  state:  " << friendi["state"].asString() << endl;
            }
            continue;
        }
        else if (msgid == LEAVE_MESSAGE_ACK) // 离线信息列表
        {
            
            Json::Value data = value["offlinemsg"];
            // data内部每一个都是string
            for (int i = 0; i < data.size(); i++)
            {
                Json::Reader reader;
                Json::Value offmsg;
                string str_offmsg = data[i].asString();
                reader.parse(str_offmsg,offmsg);
                // 转化
                cout << "[  " << i + 1 << "  ]----"
                    <<"【 "<<offmsg["time"].asString()<<" 】" << "id:  " << offmsg["id"].asInt() << "  name:  " << offmsg["name"].asString()<<"  message:  "<<offmsg["message"].asString()<<endl;
            }
            continue;
        }
    }
}
